package routerServer

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/SyncMap"
	"gitee.com/fierce_wolf/go-fox-edge-kernel-common/gatewayRouter"
	"github.com/afex/hystrix-go/hystrix"
	"github.com/gin-gonic/gin"
	"go-fox-edge-kernel-gateway/token"
	"io"
	"net/http"
	"strings"
	"sync"
)

type routerHandler struct {
	router sync.Map
}

func (e *routerHandler) registerRouter() {
	vos, err := gatewayRouter.GetRouterConfig()
	if err != nil {
		return
	}

	for _, vo := range vos {
		serviceId, redirectPath, relativePath, err := gatewayRouter.GetRouterVOParams(vo)
		if err != nil {
			continue
		}

		Method.HasEmpty(serviceId, redirectPath, relativePath)
		if !strings.HasSuffix(relativePath, "/**") {
			continue
		}
		relativePath = relativePath[0 : len(relativePath)-len("/**")]

		// 注册路由
		e.register(serviceId, relativePath, redirectPath)
	}
}

func (e *routerHandler) register(serviceId string, relativePath string, redirectPath string) {
	if relativePath == "" || redirectPath == "" {
		return
	}

	// 检测：是否已经注册该路由
	if val, err := SyncMap.GetValue(&e.router, "redirectPath", redirectPath); err == nil && val != nil {
		return
	} else {
		SyncMap.SetValue(&e.router, "redirectPath", redirectPath, true)
	}

	// 检测：是否已经注册该资源
	if val, err := SyncMap.GetValue(&e.router, "relativePath", relativePath); err == nil && val != nil {
		return
	} else {
		SyncMap.SetValue(&e.router, "relativePath", relativePath, true)
	}

	engine.GET(relativePath+"/*res", func(context *gin.Context) {
		e.handleRequest(context, serviceId, relativePath, "GET", redirectPath)
	})
	engine.DELETE(relativePath+"/*res", func(context *gin.Context) {
		e.handleRequest(context, serviceId, relativePath, "DELETE", redirectPath)
	})
	engine.PUT(relativePath+"/*res", func(context *gin.Context) {
		e.handleRequest(context, serviceId, relativePath, "PUT", redirectPath)
	})
	engine.POST(relativePath+"/*res", func(context *gin.Context) {
		e.handleRequest(context, serviceId, relativePath, "POST", redirectPath)
	})
}

func (e *routerHandler) handleRequest(context *gin.Context, serviceId string, relativePath string, method string, redirectPath string) {
	res := context.Param("res")
	commandName := relativePath + res

	// 使用 Hystrix 实现服务熔断
	hystrix.ConfigureCommand(commandName, hystrix.CommandConfig{
		Timeout:               60 * 1000, // 超时时间（毫秒）
		MaxConcurrentRequests: 10,        // 最大并发请求数
		ErrorPercentThreshold: 25,        // 错误百分比阈值
	})

	hystrix.Do(commandName, func() error {
		// 获取客户端传入的 token
		tokenStr := context.GetHeader("Authorization")
		if len(tokenStr) < len("Bearer ") {
			return errors.New("无效的token")
		}

		// 检测：是否包好Bearer，POSTMAN发送就可能包含
		if "Bearer " == tokenStr[0:len("Bearer ")] {
			tokenStr = tokenStr[len("Bearer "):]
		}

		// 验证toke的有效性
		tkn, clm, err := token.ParseToken(tokenStr)
		if err != nil {
			return err
		}
		if !tkn.Valid || clm.Valid() != nil {
			return errors.New("无效的token")
		}

		// 申请转发请求
		request, err := e.newRequest(context, method, redirectPath, res)
		if err != nil {
			return err
		}

		// 添加认证 token
		request.Header.Set("Authorization", tokenStr)
		request.Header.Set("Content-Type", "application/json")

		// 发送请求
		resp, err := http.DefaultClient.Do(request)
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		body, err := io.ReadAll(resp.Body)

		// 将目标服务的响应返回给客户端
		context.Status(resp.StatusCode)
		_, err = context.Writer.Write(body)
		return err
	}, func(err error) error {
		// 处理熔断
		context.JSON(http.StatusServiceUnavailable, gin.H{"error": "Service unavailable,err=" + err.Error()})
		return nil
	})
}

func (e *routerHandler) newRequest(context *gin.Context, method string, redirectPath string, res string) (*http.Request, error) {
	if method == "GET" || method == "DELETE" {
		url := redirectPath + res
		if context.Request.URL.RawQuery != "" {
			url += "?" + context.Request.URL.RawQuery
		}

		// 创建请求
		req, err := http.NewRequest(method, url, nil)
		if err != nil {
			return nil, err
		}

		return req, nil
	}
	if method == "POST" || method == "PUT" {
		// 创建请求
		req, err := http.NewRequest(method, redirectPath+res, context.Request.Body)
		if err != nil {
			return nil, err
		}

		return req, nil
	}

	return nil, errors.New("不支持的操作")

}
